package com.freecloud.tomcat.bio;

import com.freecloud.tomcat.bio.http.FreeRequest;
import com.freecloud.tomcat.bio.http.FreeResponse;
import com.freecloud.tomcat.bio.http.FreeServlet;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * tomcat启动类
 *
 * @Author: maomao
 * @Date: 2021/8/30 10:02 上午
 */
public class NettyTomcatMain {

    private int port = 8088;

    private Properties webxml = new Properties();
    private Map<String, FreeServlet> servletMap = new HashMap<>();

    public static void main(String[] args) {
        new NettyTomcatMain().start();
    }

    public void start() {
        //解析配置文件
        init();
        //boss线程
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //工作线程
        EventLoopGroup workGroup = new NioEventLoopGroup();
        //创建netty服务器对象
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {
            serverBootstrap.group(bossGroup, workGroup)
                //配置主线程处理逻辑
                .channel(NioServerSocketChannel.class)
                //子线程的回调处理
                .childHandler(new ChannelInitializer() {
                    @Override
                    protected void initChannel(Channel client) throws Exception {
                        //处理回调逻辑，注意责任链顺序
                        //链式编程，责任链模式

                        //响应结果编码
                        client.pipeline().addLast(new HttpResponseEncoder());
                        //用户请求解码
                        client.pipeline().addLast(new HttpRequestDecoder());
                        //自定义业务逻辑
                        client.pipeline().addLast(new FreeTomcatHandler());
                    }
                })
                //配置主线程的最大线程数
                .option(ChannelOption.SO_BACKLOG, 128)
                //保持长连接
                .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = serverBootstrap.bind(this.port).sync();
            System.out.println("Netty Tomcat start 监听端口：" + this.port);
            f.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }

    }

    private void init() {
        String web_info = this.getClass().getResource("/").getPath();
        try {
            FileInputStream fin = new FileInputStream(web_info + "web.properties");
            webxml.load(fin);
            for (Object k : webxml.keySet()) {
                String key = k.toString();
                if (key.endsWith("url")) {
                    String servletName = key.replaceAll("\\.url$", "");
                    String url = webxml.getProperty(key);
                    String className = webxml.getProperty(servletName + ".className");
                    FreeServlet freeServlet = (FreeServlet)Class.forName(className).newInstance();
                    //url与servlet绑定
                    servletMap.put(url, freeServlet);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class FreeTomcatHandler extends ChannelInboundHandlerAdapter {

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (!(msg instanceof HttpRequest)) {
                return;
            }
            HttpRequest req = (HttpRequest)msg;
            FreeResponse response = new FreeResponse(ctx, req);
            FreeRequest request = new FreeRequest(ctx, req);
            if (!servletMap.containsKey(request.getUrl())) {
                response.write("404 not find!");
                return;
            }
            servletMap.get(request.getUrl()).service(request, response);
        }
    }
}
